package com.white.camlib;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author ytf
 * Created by on 2021/06/05 12:33
 */
public class TrackerView extends SurfaceView implements SurfaceHolder.Callback {

    private Paint mPaint;
    private List<TrackerDataBundle> datas;
    private final Object lock = new byte[0];
    private Path mRectPath;

    private float scale = 1.0f;
    private float scaleCenterX, scaleCenterY;
    public void setScale(float scale, float x, float y) {
        this.scale = scale;
        scaleCenterX = x;
        scaleCenterY = y;
    }

    public TrackerView(Context context) {
        this(context, null);
    }

    public TrackerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TrackerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);

        mRectPath = new Path();
        datas = new ArrayList<>();
        getHolder().addCallback(this);

        setZOrderOnTop(true);
        setZOrderMediaOverlay(true);
    }

    public void postDatas(List<TrackerDataBundle> d){
        synchronized (lock){
            datas.clear();
            datas.addAll(d);
            lock.notify();
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if(mThread == null){
            mThread = new DrawThread(holder);
            mThread.start();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if(mThread != null){
            mThread.notifySizeChanged(width, height);
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if(mThread != null){
            mThread.exit();
            mThread = null;
        }
    }

    private DrawThread mThread;

    private class DrawThread extends Thread {

        private volatile AtomicBoolean flag = new AtomicBoolean(false);
        private SurfaceHolder mHolder;
        private AtomicInteger width, height;

        private final Object innerLock = new byte[0];

        public void notifySizeChanged(int wid, int hei){
            synchronized (innerLock){
                width.set(wid);
                height.set(hei);
                innerLock.notify();
            }
        }

        public DrawThread(SurfaceHolder h) {
            super("surfacedraw");
            mHolder = h;
            width = new AtomicInteger(0);
            height = new AtomicInteger(0);
        }

        public void exit(){
            flag.set(true);
        }

        @Override
        public void run() {
            super.run();
            while (!flag.get()){
                try {
                    if(width.get() == 0 || height.get() == 0){
                        synchronized (innerLock){
                            innerLock.wait();
                        }
                    }
                    Canvas canvas = mHolder.lockCanvas();
//                    mHolder.setFormat(PixelFormat.TRANSPARENT);
                    synchronized (lock){
                        if(datas.size() > 0){
                            for (TrackerDataBundle d : datas){
                                RectF rect = d.rect;
                                List<PointF> ps = d.points;

                                if(rect != null){
                                    if(scale != 1f){
                                        drawRect(canvas, applyScale(rect), d.colorRect);
                                    }else{
                                        drawRect(canvas, rect, d.colorRect);
                                    }
                                }
                                if(ps != null){
                                    if(scale != 1f){
                                        drawPoint(canvas, applyScale(ps), d.colorPoint);
                                    }else{
                                        drawPoint(canvas, ps, d.colorPoint);
                                    }
                                }
                            }
                            datas.clear();
                        }else{
                            canvas.drawColor(Color.TRANSPARENT);
                            lock.wait();
                        }
                    }
                    mHolder.unlockCanvasAndPost(canvas);
                    SystemClock.sleep(15);
                }catch (Exception e){

                }
            }
        }

        private RectF applyScale(RectF srcRect){

            float[] src = new float[]{
                    srcRect.left, srcRect.top,
                    srcRect.right, srcRect.bottom};
            float[] dst = new float[4];
            Matrix mx = new Matrix();
            mx.setScale(scale, scale);
            mx.mapPoints(dst, src);
            return new RectF(dst[0], dst[1], dst[2], dst[3]);
        }

        private List<PointF> applyScale(List<PointF> src){
            List<PointF> dst = new ArrayList<>();
            float[] srcPoints = new float[src.size() * 2];
            float[] dstPoints = new float[src.size() * 2];
            for (int i = 0; i < src.size(); i++) {
                srcPoints[2 * i] = src.get(i).x;
                srcPoints[2 * i + 1] = src.get(i).y;
            }
            Matrix mx = new Matrix();
            mx.setScale(scale, scale);
            mx.mapPoints(dstPoints, srcPoints);
            for (int i = 0; i < src.size(); i++) {
                dst.add(new PointF(dstPoints[2*i], dstPoints[2*i+1]));
            }
            return dst;
        }


        private void drawRect(Canvas canvas, RectF rect, int color){
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(2);
            mPaint.setColor(color);
            canvas.drawRect(rect, mPaint);
//            int delta = 40;
        }

        private void drawPoint(Canvas canvas, List<PointF> points, int color){
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(5);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setColor(color);
            for (PointF f : points){
                canvas.drawPoint(f.x, f.y, mPaint);
            }
            if(points.size() >= 5){
                PointF center = points.get(2);
                mPaint.setStrokeWidth(1);
                PointF lt = points.get(0);
                PointF rt = points.get(1);
                PointF lb = points.get(3);
                PointF rb = points.get(4);
                canvas.drawLine(lt.x, lt.y, center.x, center.y, mPaint);
                canvas.drawLine(rt.x, rt.y, center.x, center.y, mPaint);
                canvas.drawLine(lb.x, lb.y, center.x, center.y, mPaint);
                canvas.drawLine(rb.x, rb.y, center.x, center.y, mPaint);
            }
        }
    }
}
